package IC.Parser;

%%


%class Lexer
%public
%function next_token
%type Token
%line
%cup
%scanerror LexicalError
%column

%state COMMENT
%state INSTRING
%state EATQUOTE
%state COMMENTREADSTAR

%eofval{
	return MakeToken(sym.EOF);
%eofval}


%{
  	private int lineOfComment;
  	private String quotedString;
  	public int GetLine() { return yyline + 1; }
  	public Token MakeToken(int id, Object value)
  	{
  		return new Token(id, yyline, yycolumn, yytext(), value);
  	}
  	
  	public Token MakeToken(int id)
  	{
  		return new Token(id, yyline, yycolumn, yytext(), null);
  	}
%}

UPPERLETTER = [A-Z]
LOWERLETTER = [a-z]
LETTER = ({UPPERLETTER}|{LOWERLETTER})
DIGIT = [0-9]
CLASSID = {UPPERLETTER}("_"|{DIGIT}|{LETTER})*
ID = {LOWERLETTER}("_"|{DIGIT}|{LETTER})*
INTEGER = (0)+|([1-9]{DIGIT}*)
WHITESPACE = (" "|\n|\t|\r)

%%
<YYINITIAL> {WHITESPACE} { }
<YYINITIAL> "=" 		{ return MakeToken(sym.ASSIGN); }
<YYINITIAL> "boolean" 	{ return MakeToken(sym.BOOLEAN); }
<YYINITIAL> "break" 	{ return MakeToken(sym.BREAK); }
<YYINITIAL> "class" 	{ return MakeToken(sym.CLASS); }
<YYINITIAL> "," 		{ return MakeToken(sym.COMMA); }
<YYINITIAL> "continue" 	{ return MakeToken(sym.CONTINUE); }
<YYINITIAL> "/" 		{ return MakeToken(sym.DIVIDE); }
<YYINITIAL> "." 		{ return MakeToken(sym.DOT); }
<YYINITIAL> "==" 		{ return MakeToken(sym.EQUAL); }
<YYINITIAL> "extends" 	{ return MakeToken(sym.EXTENDS); }
<YYINITIAL> "else" 		{ return MakeToken(sym.ELSE); }
<YYINITIAL> "false" 	{ return MakeToken(sym.FALSE); }
<YYINITIAL> ">" 		{ return MakeToken(sym.GT); }
<YYINITIAL> ">=" 		{ return MakeToken(sym.GTE); }
<YYINITIAL> "if" 		{ return MakeToken(sym.IF); }
<YYINITIAL> "int" 		{ return MakeToken(sym.INT); }
<YYINITIAL> "&&" 		{ return MakeToken(sym.LAND); }
<YYINITIAL> "[" 		{ return MakeToken(sym.LB); }
<YYINITIAL> "(" 		{ return MakeToken(sym.LP); }
<YYINITIAL> "{" 		{ return MakeToken(sym.LCBR); }
<YYINITIAL> "length" 	{ return MakeToken(sym.LENGTH); }
<YYINITIAL> "new" 		{ return MakeToken(sym.NEW); }
<YYINITIAL> "!" 		{ return MakeToken(sym.LNEG); }
<YYINITIAL> "||" 		{ return MakeToken(sym.LOR); }
<YYINITIAL> "<" 		{ return MakeToken(sym.LT); }
<YYINITIAL> "<=" 		{ return MakeToken(sym.LTE); }
<YYINITIAL> "-" 		{ return MakeToken(sym.MINUS); }
<YYINITIAL> "%" 		{ return MakeToken(sym.MOD); }
<YYINITIAL> "*" 		{ return MakeToken(sym.MULTIPLY); }
<YYINITIAL> "!=" 		{ return MakeToken(sym.NEQUAL); }
<YYINITIAL> "null" 		{ return MakeToken(sym.NULL); }
<YYINITIAL> "+" 		{ return MakeToken(sym.PLUS); }
<YYINITIAL> "]" 		{ return MakeToken(sym.RB); }
<YYINITIAL> "}" 		{ return MakeToken(sym.RCBR); }
<YYINITIAL> "return" 	{ return MakeToken(sym.RETURN); }
<YYINITIAL> ")" 		{ return MakeToken(sym.RP); }
<YYINITIAL> ";" 		{ return MakeToken(sym.SEMI); }
<YYINITIAL> "static" 	{ return MakeToken(sym.STATIC); }
<YYINITIAL> "string" 	{ return MakeToken(sym.STRING); }

<YYINITIAL> "\""		{ yybegin(INSTRING); }
<YYINITIAL> "\"\""		{ return MakeToken(sym.QUOTE, ""); }
<INSTRING>	(\\t|\\n|\\r|\\\\|[^\\\"\n\r]|(\\\")|" "|\(|\))*
						{
						  yybegin(EATQUOTE);
						  quotedString =  yytext();
						}
<EATQUOTE>	"\""		{ 
						  yybegin(YYINITIAL); 
						  return MakeToken(sym.QUOTE, quotedString);
						}
						
<EATQUOTE>	.			{ throw new LexicalError("Found illegal char in quote (maybe new line). char:" + yytext(), yyline + 1, yycolumn); }

<YYINITIAL> "this" 		{ return MakeToken(sym.THIS); }
<YYINITIAL> "true" 		{ return MakeToken(sym.TRUE); }
<YYINITIAL> "void" 		{ return MakeToken(sym.VOID); }
<YYINITIAL> "while" 	{ return MakeToken(sym.WHILE); }
<YYINITIAL> "0"+[1-9]   { 
							throw new LexicalError("Found illegal number representation. None zero number can't start with 0.", yyline + 1, yycolumn); 
						}
<YYINITIAL> {INTEGER}({UPPERLETTER}|{LOWERLETTER})+	
						{
							throw new LexicalError("Found illegal Identifier : \'" + yytext() + "\'", yyline + 1, yycolumn);
						}
<YYINITIAL> {INTEGER} 	{ return MakeToken(sym.INTEGER, Integer.valueOf(yytext())); }
<YYINITIAL> {CLASSID} 	{ return MakeToken(sym.CLASS_ID, yytext()); }
<YYINITIAL> {ID} 		{ return MakeToken(sym.ID, yytext()); }

<YYINITIAL> "//".*					{ }

<YYINITIAL> "/*"					{ yybegin(COMMENT); lineOfComment = yyline + 1;}
<COMMENT> 	"*"						{ yybegin(COMMENTREADSTAR); }
<COMMENT>   [^*]*					{}
<COMMENT> {WHITESPACE}				{}
<COMMENTREADSTAR>	"/"				{ yybegin(YYINITIAL);}
<COMMENTREADSTAR>	"*"				{}
<COMMENTREADSTAR>	(.|{WHITESPACE}) { yybegin(COMMENT); }

<COMMENT, COMMENTREADSTAR>  <<EOF>>		{ throw new LexicalError("Lexical error: Unclosed comment.", lineOfComment); }
<YYINITIAL>  <<EOF>>					{ return MakeToken(sym.EOF); }
<EATQUOTE>  <<EOF>>						{ throw new LexicalError("Unclosed quotes.", yyline + 1, yycolumn); }		

<YYINITIAL> [^" "\n\r\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"\+\-\*\/\.,><=\|&\{\}\]\[\)\(;%\!][^" "\r\n\t]* 
	{throw new LexicalError("Lexical error: illegal character '" + yytext() + "'" , yyline + 1, yycolumn); }
